<!DOCTYPE html>
<html lang="zh-cn">
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Zhou Wei <zromyk@163.com>">
  <title>Makefile</title>
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="stylesheet" href="/style/html/pure.css">
  <link rel="stylesheet" href="/style/html/main.css">
  <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.css">
  <!-- <link rel="stylesheet" href="https://apps.bdimg.com/libs/highlight.js/9.1.0/styles/default.min.css"> -->
<link rel="stylesheet" href="/style/article/highlight/default.min.css">
<link rel="stylesheet" href="/style/article/pell-1.0.6/dist/pell.css">

</head>
<body>
  <div id="menu-background"></div>
  <div id="menu">
    <div class="pure-menu pure-menu-horizontal">
  <ul class="pure-menu-list block-middle">
    <li class="pure-menu-item">
  <a class="pure-menu-heading" href="/index.html">ZROMYK</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/index.html">主页</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/archive/index.html">归档</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/download/index.html">下载</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/feedback/index.html">反馈</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="/public/about/index.html">关于我</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link" href="https://github.com/zromyk"><i class="fa fa-github" style="font-size:32px"></i></a>
</li>

  </ul>
</div>

  </div>
  <div id="layout">
    <div class="content">
      <div id="nav">
    <div id="navigation" class="navigation">
  <ul class="pure-menu-list">
    <li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#_1">第二章 关于程序的编译和链接</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#_2">一、程序编译的基本过程</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#makefile">第三章 Makefile 介绍</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#makefile_1">一、Makefile 的基本规则</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#_3">二、一个示例</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#make">三、make 是如何工作的</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#makefile_2">四、简化 makefile</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#make_1">五、让 make 自动推导</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#_4">六、清空目标文件的规则</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav2" onclick="animateByNav()" href="#makefile_3">第四章 Makefile 总述</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#makefile_4">一、Makefile 里有什么？</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#makefile_5">二、Makefile 的文件名</a>
</li>
<li class="pure-menu-item">
  <a class="pure-menu-link nav3" onclick="animateByNav()" href="#makefile_6">三、引用其它的 Makefile</a>
</li>

  </ul>
</div>

</div>
<div id="content-articles">
  <h1 id="Makefile" class="content-subhead">Makefile</h1>
  <p>
    <span>2021-04-20</span>
    <span><span class="post-category post-category-other">Makefile</span></span>
    <button id="button-markdownEditor" class="pure-button" onclick="markdownEditor()">启用编辑</button>
    <button id="button-save" class="pure-button" onclick="save()">保存</button>
  </p>
  <div id="content-articles-markdownEditor" style="display: none;">
    <h1>编辑 power by pell</h1>
    <div id="editor" class="pell"></div>
    <div style="margin-top:20px;">
        <h3>Text output:</h3>
        <div id="text-output"></div>
    </div>
    <div style="margin-top:20px;">
        <h3>HTML output:</h3>
        <pre id="html-output"></pre>
    </div>
  </div>
  <div id="content-articles-markdown">
    <h2 id="_1">第二章 关于程序的编译和链接</h2>
<h3 id="_2">一、程序编译的基本过程</h3>
<p><img class="pure-img" alt="345678" src="https://zromyk.gitee.io/myblog-figurebed/post/Makefile.assets/345678.png" /></p>
<p>预处理</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ -E test.cpp -o test.i   

# 预处理(Preprocessing) 
# 预处理器 cpp 
# 生成预处理后的.i文件
</code></span></code></pre>
<p>编译（compile）</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ -S test.i   -o test.s   

# 编译 (Compilation) 
# 编译器 cc1plus 
# 生成汇编.s文件
</code></span></code></pre>
<p>汇编</p>
<p>检测程序语法，函数，变量是否被声明。如果函数未被声明，编译器会给出一个警告，但可以生成目标文件 （Object File，O 文件或者 OBJ 文件）</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">g++ -c test.s   -o test.o   

# 汇编  (Assembly) 
# 汇编器 as 
# 生成二进制.o文件
</code></span></code></pre>
<p>链接（link）</p>
<p>编译器在目标文件（Object File）中寻找函数的实现，如果找不到，就会报链接错误码（Linker Error）</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-SHELL">g++    test.o   -o test.out 

# 链接  (Linking) 
# 链接器 ld 
# 生成二进制.out可执行文件 
</code></span></code></pre>
<h2 id="makefile">第三章 Makefile 介绍</h2>
<h3 id="makefile_1">一、Makefile 的基本规则</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">target ... : prerequisites ...
    command
    ...
    ...
</code></span></code></pre>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>target</code></span> 是一个目标文件，可以是 </p>
<ul>
<li>Object File</li>
<li>可执行文件</li>
<li>标签（Label）</li>
</ul>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>prerequisites</code></span> 生成 target 需要的文件。</p>
<p><span style="overflow-x: auto; max-width:100%; display:inline;"><code>command</code></span> 是 make 需要执行的命令。（任意 shell 命令）</p>
<ul>
<li>prerequisites 中的文件，有任意一个文件比 target 文件新的话，command 所定义的命令就会被执行。</li>
</ul>
<h3 id="_3">二、一个示例</h3>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">edit : main.o kbd.o command.o display.o insert.o search.o files.o utils.o
    cc -o edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o 

main.o : main.c defs.h
    cc -c main.c 
kbd.o : kbd.c defs.h command.h
    cc -c kbd.c
command.o : command.c defs.h command.h
    cc -c command.c
display.o : display.c defs.h buffer.h
    cc -c display.c
insert.o : insert.c defs.h buffer.h
    cc -c insert.c
search.o : search.c defs.h buffer.h
    cc -c search.c
files.o : files.c defs.h buffer.h command.h
    cc -c files.c
utils.o : utils.c defs.h
    cc -c utils.c

clean :
    rm edit main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
</code></span></code></pre>
<h3 id="make">三、make 是如何工作的</h3>
<ol>
<li>make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。</li>
<li>如果找到，他会找文件中的第一个目标文件（target）。</li>
<li>如果 target 文件不存在，或者 prerequisites 中有文件的修改时间要比 target 新，那么就会执行后面的 command 定义的命令。</li>
<li>如果 command 中需要的 .o 文件也存在，那么 make 会在当前文件中找目标为 .o 文件的依赖性，如果找到，则再根据依赖规则生成 .o 文件。</li>
<li>&hellip;</li>
<li>最后依赖所需的文件一定是 .c 和 .h 文件，于是 make 会将他们生成 .o 文件，最后层层返回，生成最后的 target 文件。</li>
</ol>
<h3 id="makefile_2">四、简化 makefile</h3>
<p>我们声明一个变量，叫 objects, OBJECTS, objs, OBJS, obj, 或是 OBJ，只要能够表示 obj 文件就行了。我们在 makefile 一开始就这样定义： </p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 
</code></span></code></pre>
<p>于是，我们就可以很方便地在我们的 makefile 中以“$(objects)”的方式来使用这个变量了，于是我们的改良版 makefile 就变成下面这个样子： </p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 

edit : $(objects)
    cc -o edit $(objects)

main.o : main.c defs.h
    cc -c main.c
kbd.o : kbd.c defs.h command.h
    cc -c kbd.c
command.o : command.c defs.h command.h
    cc -c command.c
display.o : display.c defs.h buffer.h
    cc -c display.c
insert.o : insert.c defs.h buffer.h
    cc -c insert.c
search.o : search.c defs.h buffer.h
    cc -c search.c
files.o : files.c defs.h buffer.h command.h
    cc -c files.c
utils.o : utils.c defs.h
    cc -c utils.c

clean :
    rm edit $(objects) 
</code></span></code></pre>
<h3 id="make_1">五、让 make 自动推导</h3>
<p>GNU 的 make 很强大，它可以自动推导文件以及文件依赖关系后面的命令，于是我们就没必 要去在每一个[.o]文件后都写上类似的命令，因为，我们的 make 会自动识别，并自己推导命令。 </p>
<p>只要 make 看到一个[.o]文件，它就会自动的把[.c]文件加在依赖关系中。</p>
<p>如果 make 找到一个 whatever.o，那么 whatever.c，就会是 whatever.o 的依赖文件。并且 cc -c whatever.c 也会被推导出来，于是，我们的 makefile 再也不用写得这么复杂。我们的 是新的 makefile 又出炉了。 </p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">objects = main.o kbd.o command.o display.o insert.o search.o files.o utils.o 

edit : $(objects)
cc -o edit $(objects) 

main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean # “.PHONY”表示，clean 是个伪目标文件
clean :
    -rm edit $(objects) 
</code></span></code></pre>
<h3 id="_4">六、清空目标文件的规则</h3>
<p>每个 Makefile 中都应该写一个清空目标文件（.o 和执行文件）的规则，这不仅便于重编 译，也很利于保持文件的清洁。</p>
<p>.PHONY 意思表示 clean 是一个“伪目标”。</p>
<p>而在 rm 命令前面加了一个小减号的意思就是，也许某些文件出现问题，但不要管，继续做后面的事。当然，clean 的规则不 要放在文件的开头，不然，这就会变成 make 的默认目标，相信谁也不愿意这样。不成文的规矩是——“clean 从来都是放在文件的最后”。 </p>
<h2 id="makefile_3">第四章 Makefile 总述</h2>
<h3 id="makefile_4">一、Makefile 里有什么？</h3>
<p>Makefile 里主要包含了五个东西：显示规则、隐晦规则、变量定义、文件指示和注释。 </p>
<p>1、<strong>显示规则。</strong>显示规则说明了，如何生成一个或多的的目标文件。这是由 Makefile 的书 写者明显指出，要生成的文件，文件的依赖文件，生成的命令。 </p>
<p>2、<strong>隐晦规则。</strong>由于我们的 make 有自动推导的功能，所以隐晦的规则可以让我们比较粗糙 地简略地书写 Makefile，这是由 make 所支持的。 </p>
<p>3、<strong>变量的定义。</strong>在 Makefile 中我们要定义一系列的变量，变量一般都是字符串，这个有 点像 C 语言中的宏，当 Makefile 被执行时，其中的变量都会被扩展到相应的引用位置上。</p>
<p>4、<strong>文件指示。</strong>其包括了三个部分，一个是在一个 Makefile 中引用另一个 Makefile，就 像 C 语言中的 include 一样；另一个是指根据某些情况指定 Makefile 中的有效部分，就 像 C 语言中的预编译#if 一样；还有就是定义一个多行的命令。有关这一部分的内容，我会 在后续的部分中讲述。 </p>
<p>5、<strong>注释。</strong>Makefile 中只有行注释，和 UNIX 的 Shell 脚本一样，其注释是用“#”字符， 这个就像 C/C++中的“//”一样。如果你要在你的 Makefile 中使用“#”字符，可以用反 斜框进行转义，如：“#”。 </p>
<p><strong>最后，还值得一提的是，在 Makefile 中的命令，必须要以[Tab]键开始。</strong> </p>
<h3 id="makefile_5">二、Makefile 的文件名</h3>
<p>默认的情况下，make 命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、 “makefile”、 “Makefile”的文件。</p>
<p>在这三个文件名中，最好使用“Makefile”这个文件名，因为，这个文件名第一个字符为大写，这样有一种显目的感觉。最好不要用“GNUmakefile”，这个文件是 GNU 的 make 识别的。</p>
<p>指定特定的 Makefile：</p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-shell">make -f [file name, like : Make.Linux]
make --file [file name]
</code></span></code></pre>
<h3 id="makefile_6">三、引用其它的 Makefile</h3>
<p>在 Makefile 使用 include 关键字可以把别的 Makefile 包含进来，这很像 C 语言的 #include，被包含的文件会原模原样的放在当前文件的包含位置。include 的语法是： </p>
<pre><code class="pre-wrap"><span style="overflow-x: auto; max-width:100%; display:inline;"><code class="language-makefile">include &lt;filename&gt; 

# filename 可以是当前操作系统 Shell 的文件模式（可以保含路径和通配符） 
</code></span></code></pre>
<p><strong>在 include 前面可以有一些空字符，但是绝不能是[Tab]键开始。</strong></p>
  </div>
</div>
 
    </div>
  </div>
  <div id="footer-background">
    <div id="footer">
      <div class="legal pure-g">
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-license"><a href="https://beian.miit.gov.cn/#/Integrated/index">浙ICP备2020038748号</a></p>
  </div>
  <div class="pure-u-1 u-sm-1-2">
    <p class="legal-links"><a href="https://github.com/zromyk">GitHub</a></p>
    <p class="legal-copyright">Copyright © 2021 Wei Zhou. 保留所有权利。</p>
  </div>
</div>
    </div>
  </div>
  <!-- <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> -->
  <script src="/style/html/jquery.min.js"></script>
  <script src='/style/article/latex/latest.js?config=TeX-MML-AM_CHTML'></script>
<!-- <script src="https://cdn.geogebra.org/apps/deployggb.js"></script> -->
<script src="/style/article/deployggb.js"></script>
<!-- <script src="https://apps.bdimg.com/libs/highlight.js/9.1.0/highlight.min.js"></script> -->
<script type="text/javascript">
  // 脚本：navigation 随鼠标移动自动变换宽度
  var element = document.getElementById("navigation"); // 获取要操作的元素
  var elementWidth = parseInt(getComputedStyle(element).width);
  var elementLeft = 0;
  var elementRight = 0;
  element.addEventListener('mouseenter', function (event) { // 添加鼠标按下事件的监听器
    elementLeft = element.getBoundingClientRect().left - 10;
    elementRight = element.getBoundingClientRect().left + elementWidth * 3;
    window.addEventListener('mousemove', resize); // 添加全局的鼠标移动事件的监听器
  });

  function resize(event) {
    var minWidth = elementWidth;
    var maxWidth = elementWidth * 2.5;
    // console.log(elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    if (elementLeft <= event.clientX && event.clientX <= elementRight) {
      var width = event.clientX - elementLeft + elementWidth / 2;
      width = Math.min(width, maxWidth);
      width = Math.max(width, minWidth);
      element.style.width = width + 'px'; // 设置新的宽度样式属性
    }
    else {
      element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
      stopResize();
    }
  }

  function stopResize() {
    element.style.width = elementWidth + 'px'; // 设置新的宽度样式属性
    // console.log("stopResize", elementLeft, event.clientX, elementRight, event.clientX - elementLeft + elementWidth / 2);
    window.removeEventListener('mousemove', resize); // 移除鼠标移动事件的监听器
  }
</script>
<script src="/style/article/highlight/highlight.min.js"></script>
<script type="text/javascript">
  // 脚本：code语法高亮
  hljs.initHighlightingOnLoad();
</script>
<script>
  function animateByNav() {
    $("html").animate({
        scrollTop: ($(event.target.hash).offset().top - 52)
    }, 300);
  };
</script>
<script src="/style/article/pell-1.0.6/dist/pell.js"></script>
<script>
  // 脚本：自由编辑页面
  var editor = window.pell.init({
    element: document.getElementById('editor'),
    defaultParagraphSeparator: 'p',
    onChange: function(html) {
        document.getElementById('text-output').innerHTML = html
        document.getElementById('html-output').textContent = html
    }
  });

  function markdownEditor() {
    var articles = document.getElementById('content-articles-markdown');
    if (articles.getAttribute("contenteditable") == "true") {
        articles.setAttribute("contenteditable", "false");
        document.getElementById("content-articles-markdownEditor").style.display = "none"; //隐藏
        document.getElementById("button-markdownEditor").innerHTML = "启用编辑";
    } else {
        articles.setAttribute("contenteditable", "true");
        document.getElementById("content-articles-markdownEditor").style.display = ""; //显示
        document.getElementById("button-markdownEditor").innerHTML = "关闭编辑";
    }
  };

  function save() {
      window.alert("保存成功");
  };
</script>

</body>
</html>
